/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef IMAGE_KNIFE_C_DECODE_INTERCEPTOR_OH_H
#define IMAGE_KNIFE_C_DECODE_INTERCEPTOR_OH_H

#include <multimedia/image_framework/image/image_source_native.h>
#include "imageknife_task_internal.h"
#include "interceptor.h"
#include "imageknife_request.h"
#include "imageknife_data_napi.h"
#include "hitrace/trace.h"
#include "pixelmap_utils.h"

namespace ImageKnifePro {
class DecodeInterceptorDefault : public DecodeInterceptor {
public:
    DecodeInterceptorDefault()
    {
        name = "Default DecodeInterceptor";
    }

    bool Resolve(std::shared_ptr<ImageKnifeTask> task) override
    {
        auto fileTypeInfo = task->GetFileTypeInfo();
        if (fileTypeInfo == nullptr) {
            task->EchoError("Unknown FileType Info");
            return false;
        }

        if (fileTypeInfo->format == ImageFormat::UNKNOWN || fileTypeInfo->format == ImageFormat::CUSTOM_FORMAT ||
            fileTypeInfo->format == ImageFormat::AVIF) {
            return false;
        }
        if (task->product.imageBuffer == nullptr) {
            task->EchoError("Empty ImageBuffer");
            return false;
        }

        auto taskInternal = std::dynamic_pointer_cast<ImageKnifeTaskInternal>(task);
        IMAGE_KNIFE_CHECK_RETURN(taskInternal == nullptr, false);
        if (taskInternal->IsFrameDecodeMode()) {
            IMAGE_KNIFE_LOG(LOG_DEBUG, "%{public}s DecodeFrame : %{public}d",
                taskInternal->GetTaskInfo().c_str(), taskInternal->GetDecodeFrameIndex());
            return DecodeFrame(taskInternal);
        } else {
            return Decode(taskInternal);
        }
    }
private:
    struct DecodeArgs {
        OH_ImageSourceNative *source = nullptr;
        OH_DecodingOptions *decodeOption = nullptr;
        ~DecodeArgs()
        {
            if (decodeOption != nullptr) {
                OH_DecodingOptions_Release(decodeOption);
            }
            if (source != nullptr) {
                OH_ImageSourceNative_Release(source);
            }
        }
    };

    bool DecodeFrame(std::shared_ptr<ImageKnifeTaskInternal> task);

    bool DecodePixelmapList(std::shared_ptr<ImageKnifeTaskInternal> task, const DecodeArgs &args,
                            OH_ImageSourceNative *source);

    OH_PixelmapNative *CreatePixelmapByAllocator(OH_ImageSourceNative *source, OH_DecodingOptions *decodeOption,
                                                 std::shared_ptr<ImageKnifeTaskInternal> task);

    OH_ImageSourceNative *GetImageSource(DecodeArgs &args, std::shared_ptr<ImageKnifeTaskInternal> task);

    IMAGE_DYNAMIC_RANGE GetDesiredDynamicRange(std::shared_ptr<ImageKnifeTask> task);

    bool Decode(std::shared_ptr<ImageKnifeTaskInternal> task)
    {
        DecodeArgs args;
        OH_ImageSourceNative *source = GetImageSource(args, task);
        if (source == nullptr) {
            return false;
        }

        if (!ConfigDecodeOption(args, task)) {
            return false;
        }

        if (task->GetFileTypeInfo()->frameCount > 1) {
            if (!DecodePixelmapList(task, args, source)) {
                return false;
            }
        } else {
            OH_PixelmapNative *pixelmap = CreatePixelmapByAllocator(source, args.decodeOption, task);
            if (pixelmap != nullptr) {
                task->product.imageData = std::make_shared<ImageData>(pixelmap);
            } else {
                return false;
            }
        }

        Orientate(task, source);
        return true;
    }

    bool ConfigDecodeOption(DecodeArgs &args, std::shared_ptr<ImageKnifeTaskInternal> &task)
    {
        // 创建解码Option
        Image_ErrorCode imgErrorCode = OH_DecodingOptions_Create(&args.decodeOption);
        if (imgErrorCode != IMAGE_SUCCESS) {
            task->EchoError("Create Decode Option Failed, error code: " + std::to_string(imgErrorCode));
            return false;
        }
        // 设置期望解码尺寸
        Image_Size imageSize = task->GetDesiredImageSize();
        if (imageSize.width != 0 && imageSize.height != 0) {
            OH_DecodingOptions_SetDesiredSize(args.decodeOption, &imageSize);
        }

        // 设置期望的动态范围
        OH_DecodingOptions_SetDesiredDynamicRange(args.decodeOption, GetDesiredDynamicRange(task));

        // 设置指定解码帧index
        if (task->IsFrameDecodeMode()) {
            OH_DecodingOptions_SetIndex(args.decodeOption, task->GetDecodeFrameIndex());
        }
        return true;
    }

    void Orientate(std::shared_ptr<ImageKnifeTask> task, OH_ImageSourceNative *source)
    {
        if (task->GetImageRequestType() != ImageRequestType::MAIN_SRC) {
            return;
        }

        auto request = task->GetImageKnifeRequest();
        IMAGE_KNIFE_CHECK(request == nullptr);
        auto option = request->GetImageKnifeOption();
        IMAGE_KNIFE_CHECK(option == nullptr);

        if (option->orientation != Orientation::AUTO) {
            return;
        }

        std::string keyStr = "Orientation";
        Image_String key = {.data = (char *)keyStr.c_str(), .size = keyStr.length()};
        Image_String value = {.data = nullptr, .size = 0};
        OH_ImageSourceNative_GetImageProperty(source, &key, &value);
        // Image_String 返回的data没有包含尾0
        std::string valueStr(value.data, value.size);
        PixelmapUtils::Orientate(task->product.imageData, valueStr);
        // 按接口说明需要释放分配的内存
        free(value.data);
    }
};
};

#endif // IMAGE_KNIFE_C_DECODE_INTERCEPTOR_OH_H
